import bmapLibs from 'bmap-libs';
import { loadResource } from './utils';
import Observer from './Observer';
import resetControl from './resetControl';
import MarkerCluster from '../plugins/MarkerClusterer_min';
import TextIconOverlay from '../plugins/TextIconOverlay_min';

// 地图库
const lib = {
  map: [`//api.map.baidu.com/getscript?v=1.0&type=webgl&ak={AK}`, '//api.map.baidu.com/res/webgl/10/bmap.css'],
  vgl: ['https://code.bdstatic.com/npm/mapvgl@1.0.0-beta.159/dist/mapvgl.min.js'],
};

/**
 * options
 * {
 *  ak, // 百度地图ak
 *  minZoom,
 *  maxZoom,
 *  lat,
 *  lng,
 *  zoom,
 *  style,  // 地图样式，支持styleId字符串或styleJson对象
 *  enableVgl: Boolean, // 开启vgl
 *  enableCluster: Boolean, // 开启聚合功能
 *  extra: Object, // 额外的初始参数
 * }
 */

export default class Map extends Observer {
  constructor($el, options) {
    super();
    this.$el = $el;
    this.options = { ...options };
    this.map = null;
  }

  init() {
    if (this.map) {
      // 已经初始化过
      this.emit('loaded', this.map);
      return;
    }
    // 加载百度地图相关脚本
    const { enableVgl } = this.options;
    let libs = [];
    let subLibs = libs;

    if (!window.BMapGL) {
      const { ak } = this.options;

      if (!ak) {
        window.alert('未找到百度地图ak，请检查配置项！');
        return;
      }

      libs.push({ src: lib.map.map((v) => v.replace('{AK}', ak)), children: [] });
      subLibs = libs[0].children;
    }
    if (enableVgl && !window.mapvgl) {
      subLibs.push(...lib.vgl);
    }

    if (libs.length) {
      const nativeContains = HTMLElement.prototype.contains;
      loadResource(libs).then(() => {
        if (nativeContains && nativeContains !== HTMLElement.prototype.contains) {
          HTMLElement.prototype.contains = nativeContains;
        }

        this.initMap();
      });
    } else {
      this.initMap();
    }
  }

  initMap() {
    if (this.$el) {
      const { enableCluster, minZoom, maxZoom, lat, lng, zoom, style, extra } = this.options;

      // 初始化地图
      this.map = new BMapGL.Map(this.$el, {
        ...extra,
        minZoom: minZoom || 5,
        maxZoom: maxZoom || 18,
        mapType: window.BMAP_NORMAL_MAP,
      });

      // 初始化控制
      this.map.enableScrollWheelZoom(); // 允许滚轮缩放
      this.map.disableDoubleClickZoom(); // 禁止双击缩放

      // 初始化中心点（默认天安门）
      this.setCenterAndZoom([lng || 116.39167, lat || 39.90333], zoom || 10, true);
      // 初始化地图样式
      this.setMapStyle(style);

      // 挂载原型方法
      const excludes = ['constructor', 'init', 'initMap'];
      Object.getOwnPropertyNames(Object.getPrototypeOf(this)).forEach((name) => {
        if (!excludes.includes(name)) {
          this.map[name] = (...args) => this[name](...args);
        }
      });

      // 挂载地图库
      bmapLibs();

      // 挂载聚合插件
      if (enableCluster) {
        TextIconOverlay();
        MarkerCluster();
      }

      // 挂载自定义控件
      BMapGL.ResetControl = resetControl();

      // 地图初始化完成事件
      this.emit('loaded', this.map);
    } else {
      throw new Error('未找到地图挂载点');
    }
  }

  /**
   * @description: 解析点位，如果不是百度的Point对象，而是数组[lng, lat]，则对其进行转换
   * @param {*} point
   * @return {*}
   */
  parsePoint(point) {
    // 如果不是百度的Point对象，而是数组[lng, lat]，则对其进行转换
    return !(point instanceof BMapGL.Point) && Array.isArray(point) ? new BMapGL.Point(...point) : point;
  }

  /**
   * @description: 设置重置点
   * @param {*} center
   * @param {*} zoom
   * @return {*}
   */
  setReset(center, zoom) {
    this.map._reset = { center: this.parsePoint(center), zoom };
  }

  /**
   * @description: 视窗重置
   * @return {*}
   */
  viewportReset() {
    if (this.map._reset) {
      // centerAndZoom设置的zoom会被取整可能会造成显示不一致，所以用setViewport效果更好
      this.map.setViewport(this.map._reset);
    } else {
      this.map.reset();
    }
  }

  /**
   * @description: 设置地图中心点和缩放
   * @param {*} center
   * @param {*} zoom
   * @param {*} animation
   * @return {*}
   */
  setCenterAndZoom(center, zoom, animation = false) {
    let _center = this.parsePoint(center);

    if (animation) {
      // 动画平移
      this.map.centerAndZoom(_center, zoom);
    } else {
      // 无动画平移
      this.map.panTo(_center, { noAnimation: true });
      this.map.setZoom(zoom);
    }
  }

  /**
   * @description: 设置地图样式
   * @param {*} style
   * @return {*}
   */
  setMapStyle(style) {
    if (style) {
      if (typeof style === 'string') {
        this.map.setMapStyleV2({
          styleId: style,
        });
      } else if (typeof style === 'object') {
        this.map.setMapStyleV2({
          styleJson: style,
        });
      }
    }
  }

  /**
   * @description: 开启卫星图层
   * @return {*}
   */
  openSatelliteLayer(type = 1) {
    switch (type) {
      case 1:
        // 自定义卫星瓦片图层（地图显示元素和地图样式一致，但是加载过程中会显示底图，影响观感）
        if (!this._satelliteLayer) {
          let tileLayer = new BMapGL.TileLayer({
            transparentPng: true,
          });
          tileLayer.zIndex = 1;
          tileLayer.getTilesUrl = function (point, level, ...args) {
            if (!point || level < 0) {
              return null;
            }
            return `//shangetu5.map.bdimg.com/it/u=x=${point.x};y=${point.y};z=${level};v=009;type=sate&fm=46`;
          };
          this._satelliteLayer = tileLayer;
        }
        this.map.addTileLayer(this._satelliteLayer);
        break;
      case 2:
        // 百度地球模式（地图显示元素可通过displayOptions做简单控制，无法做细粒度控制）
        this.map.setMapType(BMAP_EARTH_MAP);
        break;
      case 3:
        // 百度卫星模式（地图显示元素太多，且没法控制，看起来太乱）
        this.map.setMapType(BMAP_SATELLITE_MAP);
        break;
    }
  }

  /**
   * @description: 关闭卫星图层
   * @return {*}
   */
  closeSatelliteLayer() {
    if (this._satelliteLayer) {
      this.map.removeTileLayer(this._satelliteLayer);
    }
    this.map.setMapType(BMAP_NORMAL_MAP);
  }

  /**
   * @description: 批量移除地图覆盖物
   * @param {array} args
   * @return {*}
   */
  removeOverlays(...args) {
    args.forEach((arg) => {
      if (Array.isArray(arg)) {
        this.removeOverlays.apply(this, arg);
      } else {
        this.map.removeOverlay(arg);
      }
    });
  }
}
